package strategies

import (
	"context"
	"fmt"
	"math"

	"github.com/gogf/gf/v2/os/gtime"

	"goldtree/internal/strategy"
)

// BollingerBandsStrategy 布林带策略
type BollingerBandsStrategy struct {
	*strategy.BaseStrategy
	period      int                    // 计算周期
	stdDev      float64               // 标准差倍数
	priceData   map[string][]float64  // 价格数据缓存
	upperBand   map[string][]float64  // 上轨数据
	lowerBand   map[string][]float64  // 下轨数据
	middleBand  map[string][]float64  // 中轨数据
	lastSignals map[string]strategy.SignalType // 最后信号
}

// NewBollingerBandsStrategy 创建布林带策略
func NewBollingerBandsStrategy() strategy.Strategy {
	return &BollingerBandsStrategy{
		BaseStrategy: strategy.NewBaseStrategy(),
		priceData:    make(map[string][]float64),
		upperBand:    make(map[string][]float64),
		lowerBand:    make(map[string][]float64),
		middleBand:   make(map[string][]float64),
		lastSignals:  make(map[string]strategy.SignalType),
	}
}

// GetInfo 获取策略信息
func (s *BollingerBandsStrategy) GetInfo() *strategy.StrategyInfo {
	return &strategy.StrategyInfo{
		Name:        "布林带策略",
		Version:     "1.0.0",
		Description: "基于布林带上下轨的突破和回归策略",
		Author:      "GoldTree",
		Parameters: []*strategy.ParameterDef{
			{
				Name:         "period",
				Type:         "int",
				DefaultValue: 20,
				MinValue:     5,
				MaxValue:     100,
				Description:  "布林带计算周期",
				Required:     true,
			},
			{
				Name:         "std_dev",
				Type:         "float",
				DefaultValue: 2.0,
				MinValue:     0.5,
				MaxValue:     5.0,
				Description:  "标准差倍数",
				Required:     true,
			},
			{
				Name:         "strategy_type",
				Type:         "string",
				DefaultValue: "mean_reversion",
				Description:  "策略类型：mean_reversion(均值回归) 或 breakout(突破)",
				Required:     true,
			},
		},
		RequiredData: []string{"kline", "price"},
	}
}

// Initialize 初始化策略
func (s *BollingerBandsStrategy) Initialize(ctx context.Context, config *strategy.StrategyConfig) error {
	// 调用基类初始化
	if err := s.BaseStrategy.Initialize(ctx, config); err != nil {
		return err
	}
	
	// 解析策略参数
	params := config.Parameters
	if period, ok := params["period"].(float64); ok {
		s.period = int(period)
	} else {
		s.period = 20 // 默认值
	}
	
	if stdDev, ok := params["std_dev"].(float64); ok {
		s.stdDev = stdDev
	} else {
		s.stdDev = 2.0 // 默认值
	}
	
	// 验证参数
	if s.period <= 4 {
		return fmt.Errorf("布林带周期必须大于4")
	}
	
	if s.stdDev <= 0 {
		return fmt.Errorf("标准差倍数必须大于0")
	}
	
	return nil
}

// OnMarketData 处理市场数据
func (s *BollingerBandsStrategy) OnMarketData(ctx context.Context, data *strategy.MarketData) ([]*strategy.Signal, error) {
	// 更新价格数据
	s.updatePriceData(data.StockCode, data.ClosePrice)
	
	// 计算布林带
	upper, middle, lower := s.calculateBollingerBands(data.StockCode)
	if upper == 0 || middle == 0 || lower == 0 {
		return nil, nil // 数据不足
	}
	
	// 生成交易信号
	signals := s.generateSignals(ctx, data, upper, middle, lower)
	
	return signals, nil
}

// OnKLineData 处理K线数据
func (s *BollingerBandsStrategy) OnKLineData(ctx context.Context, kline *strategy.KLineData) ([]*strategy.Signal, error) {
	// 转换为市场数据格式
	marketData := &strategy.MarketData{
		StockCode:   kline.StockCode,
		Price:       kline.ClosePrice,
		Volume:      kline.Volume,
		Timestamp:   kline.Timestamp,
		OpenPrice:   kline.OpenPrice,
		HighPrice:   kline.HighPrice,
		LowPrice:    kline.LowPrice,
		ClosePrice:  kline.ClosePrice,
		Change:      kline.Change,
		ChangeRatio: kline.ChangeRatio,
	}
	
	return s.OnMarketData(ctx, marketData)
}

// Validate 验证策略配置
func (s *BollingerBandsStrategy) Validate(config *strategy.StrategyConfig) error {
	params := config.Parameters
	
	// 验证周期
	if period, ok := params["period"]; ok {
		if p, ok := period.(float64); !ok || p <= 4 || p > 100 {
			return fmt.Errorf("布林带周期必须是5-100之间的整数")
		}
	}
	
	// 验证标准差倍数
	if stdDev, ok := params["std_dev"]; ok {
		if sd, ok := stdDev.(float64); !ok || sd <= 0 || sd > 5 {
			return fmt.Errorf("标准差倍数必须是0.5-5之间的数值")
		}
	}
	
	// 验证策略类型
	if strategyType, ok := params["strategy_type"]; ok {
		if st, ok := strategyType.(string); !ok || (st != "mean_reversion" && st != "breakout") {
			return fmt.Errorf("策略类型必须是 mean_reversion 或 breakout")
		}
	}
	
	return nil
}

// updatePriceData 更新价格数据
func (s *BollingerBandsStrategy) updatePriceData(stockCode string, price float64) {
	// 初始化数据
	if _, exists := s.priceData[stockCode]; !exists {
		s.priceData[stockCode] = make([]float64, 0)
		s.upperBand[stockCode] = make([]float64, 0)
		s.lowerBand[stockCode] = make([]float64, 0)
		s.middleBand[stockCode] = make([]float64, 0)
	}
	
	// 添加新价格
	s.priceData[stockCode] = append(s.priceData[stockCode], price)
	
	// 保持数据窗口大小
	maxLength := s.period * 2 // 保留更多历史数据
	if len(s.priceData[stockCode]) > maxLength {
		s.priceData[stockCode] = s.priceData[stockCode][len(s.priceData[stockCode])-maxLength:]
	}
}

// calculateBollingerBands 计算布林带
func (s *BollingerBandsStrategy) calculateBollingerBands(stockCode string) (upper, middle, lower float64) {
	prices := s.priceData[stockCode]
	if len(prices) < s.period {
		return 0, 0, 0 // 数据不足
	}
	
	// 计算移动平均线（中轨）
	sum := 0.0
	start := len(prices) - s.period
	for i := start; i < len(prices); i++ {
		sum += prices[i]
	}
	middle = sum / float64(s.period)
	
	// 计算标准差
	variance := 0.0
	for i := start; i < len(prices); i++ {
		diff := prices[i] - middle
		variance += diff * diff
	}
	stdDeviation := math.Sqrt(variance / float64(s.period))
	
	// 计算上轨和下轨
	upper = middle + s.stdDev*stdDeviation
	lower = middle - s.stdDev*stdDeviation
	
	// 保存布林带数据
	s.upperBand[stockCode] = append(s.upperBand[stockCode], upper)
	s.middleBand[stockCode] = append(s.middleBand[stockCode], middle)
	s.lowerBand[stockCode] = append(s.lowerBand[stockCode], lower)
	
	// 保持数据窗口大小
	if len(s.upperBand[stockCode]) > 100 {
		s.upperBand[stockCode] = s.upperBand[stockCode][1:]
		s.middleBand[stockCode] = s.middleBand[stockCode][1:]
		s.lowerBand[stockCode] = s.lowerBand[stockCode][1:]
	}
	
	return upper, middle, lower
}

// generateSignals 生成交易信号
func (s *BollingerBandsStrategy) generateSignals(ctx context.Context, data *strategy.MarketData, upper, middle, lower float64) []*strategy.Signal {
	var signals []*strategy.Signal
	
	// 获取策略类型
	strategyType := "mean_reversion" // 默认均值回归
	if config := s.GetContext().Config; config != nil {
		if st, ok := config.Parameters["strategy_type"].(string); ok {
			strategyType = st
		}
	}
	
	var signalType strategy.SignalType
	var reason string
	var confidence float64
	
	currentPrice := data.ClosePrice
	
	if strategyType == "mean_reversion" {
		// 均值回归策略
		if currentPrice <= lower {
			// 价格触及下轨，买入信号
			signalType = strategy.SignalBuy
			reason = fmt.Sprintf("布林带下轨支撑：价格%.2f触及下轨%.2f，预期反弹", currentPrice, lower)
			confidence = s.calculateMeanReversionConfidence(currentPrice, upper, middle, lower, true)
		} else if currentPrice >= upper {
			// 价格触及上轨，卖出信号
			signalType = strategy.SignalSell
			reason = fmt.Sprintf("布林带上轨阻力：价格%.2f触及上轨%.2f，预期回落", currentPrice, upper)
			confidence = s.calculateMeanReversionConfidence(currentPrice, upper, middle, lower, false)
		} else {
			return nil // 无信号
		}
	} else {
		// 突破策略
		// 需要历史数据判断突破
		upperList := s.upperBand[data.StockCode]
		lowerList := s.lowerBand[data.StockCode]
		priceList := s.priceData[data.StockCode]
		
		if len(upperList) < 2 || len(lowerList) < 2 || len(priceList) < 2 {
			return nil
		}
		
		prevPrice := priceList[len(priceList)-2]
		prevUpper := upperList[len(upperList)-2]
		prevLower := lowerList[len(lowerList)-2]
		
		if prevPrice <= prevUpper && currentPrice > upper {
			// 向上突破上轨
			signalType = strategy.SignalBuy
			reason = fmt.Sprintf("布林带上轨突破：价格从%.2f突破上轨%.2f", prevPrice, upper)
			confidence = s.calculateBreakoutConfidence(currentPrice, upper, middle, lower, true)
		} else if prevPrice >= prevLower && currentPrice < lower {
			// 向下突破下轨
			signalType = strategy.SignalSell
			reason = fmt.Sprintf("布林带下轨突破：价格从%.2f跌破下轨%.2f", prevPrice, lower)
			confidence = s.calculateBreakoutConfidence(currentPrice, upper, middle, lower, false)
		} else {
			return nil // 无信号
		}
	}
	
	// 检查是否重复信号
	lastSignal, exists := s.lastSignals[data.StockCode]
	if exists && lastSignal == signalType {
		return nil // 避免重复信号
	}
	
	// 创建信号
	signal := &strategy.Signal{
		StrategyID: s.GetContext().Config.ID,
		StockCode:  data.StockCode,
		SignalType: signalType,
		Price:      data.Price,
		Quantity:   s.calculateQuantity(data, currentPrice, upper, middle, lower),
		Confidence: confidence,
		Reason:     reason,
		Timestamp:  gtime.Now(),
		ExtraData: map[string]interface{}{
			"upper_band":    upper,
			"middle_band":   middle,
			"lower_band":    lower,
			"current_price": currentPrice,
			"strategy_type": strategyType,
			"volume":        data.Volume,
		},
	}
	
	signals = append(signals, signal)
	
	// 记录最后信号
	s.lastSignals[data.StockCode] = signalType
	
	return signals
}

// calculateMeanReversionConfidence 计算均值回归置信度
func (s *BollingerBandsStrategy) calculateMeanReversionConfidence(price, upper, middle, lower float64, isBuy bool) float64 {
	baseConfidence := 0.6
	
	var distance float64
	var bandWidth float64 = upper - lower
	
	if isBuy {
		// 买入信号：价格越接近下轨，置信度越高
		distance = math.Abs(price - lower)
		// 价格越深入下轨下方，置信度越高
		if price < lower {
			distance = lower - price
		}
	} else {
		// 卖出信号：价格越接近上轨，置信度越高
		distance = math.Abs(price - upper)
		// 价格越深入上轨上方，置信度越高
		if price > upper {
			distance = price - upper
		}
	}
	
	// 根据价格偏离程度调整置信度
	distanceRatio := distance / bandWidth
	confidenceBonus := math.Min(distanceRatio*0.3, 0.3)
	
	confidence := baseConfidence + confidenceBonus
	
	// 限制在0-1范围内
	if confidence > 1.0 {
		confidence = 1.0
	}
	if confidence < 0.0 {
		confidence = 0.0
	}
	
	return confidence
}

// calculateBreakoutConfidence 计算突破置信度
func (s *BollingerBandsStrategy) calculateBreakoutConfidence(price, upper, middle, lower float64, isBuy bool) float64 {
	baseConfidence := 0.7 // 突破信号基础置信度较高
	
	var strength float64
	bandWidth := upper - lower
	
	if isBuy {
		// 向上突破：突破幅度越大，置信度越高
		strength = math.Max(0, price-upper) / bandWidth
	} else {
		// 向下突破：突破幅度越大，置信度越高
		strength = math.Max(0, lower-price) / bandWidth
	}
	
	confidenceBonus := math.Min(strength*0.2, 0.2)
	confidence := baseConfidence + confidenceBonus
	
	// 限制在0-1范围内
	if confidence > 1.0 {
		confidence = 1.0
	}
	if confidence < 0.0 {
		confidence = 0.0
	}
	
	return confidence
}

// calculateQuantity 计算交易数量
func (s *BollingerBandsStrategy) calculateQuantity(data *strategy.MarketData, price, upper, middle, lower float64) int {
	baseQuantity := 100
	
	// 根据价格相对位置调整数量
	bandWidth := upper - lower
	pricePosition := (price - lower) / bandWidth // 0-1之间
	
	var multiplier float64 = 1.0
	
	// 均值回归策略：在极端位置加大仓位
	if pricePosition <= 0.1 || pricePosition >= 0.9 {
		multiplier = 2.0
	} else if pricePosition <= 0.2 || pricePosition >= 0.8 {
		multiplier = 1.5
	}
	
	// 根据价格调整基础数量
	if data.Price > 100 {
		baseQuantity = 50
	} else if data.Price > 50 {
		baseQuantity = 100
	} else {
		baseQuantity = 200
	}
	
	return int(float64(baseQuantity) * multiplier)
}

// 注册策略
func init() {
	// 注册参数配置
	configManager := strategy.GetConfigManager()
	params := []*strategy.ParameterConfig{
		{
			Name:         "period",
			Type:         strategy.ParamTypeInt,
			DefaultValue: 20,
			Required:     true,
			Description:  "布林带计算周期",
			Label:        "计算周期",
			Group:        "基础参数",
			Order:        1,
			Validator:    &strategy.IntValidator{Min: intPtr(5), Max: intPtr(100)},
		},
		{
			Name:         "std_dev",
			Type:         strategy.ParamTypeFloat,
			DefaultValue: 2.0,
			Required:     true,
			Description:  "标准差倍数",
			Label:        "标准差倍数",
			Group:        "基础参数",
			Order:        2,
			Validator:    &strategy.FloatValidator{Min: floatPtr(0.5), Max: floatPtr(5.0)},
		},
		{
			Name:         "strategy_type",
			Type:         strategy.ParamTypeString,
			DefaultValue: "mean_reversion",
			Required:     true,
			Description:  "策略类型：mean_reversion(均值回归) 或 breakout(突破)",
			Label:        "策略类型",
			Group:        "策略参数",
			Order:        3,
			Validator:    &strategy.StringValidator{Options: []string{"mean_reversion", "breakout"}},
		},
	}
	
	configManager.RegisterParameterSchema("bollinger", params)
}